package com.beta.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.framework.service.impl.SuperServiceImpl;
import com.baomidou.mybatisplus.plugins.Page;
import com.beta.dto.product.ProductItemDto;
import com.beta.dto.product.ProductItemOptions;
import com.beta.dto.product.ProductItemQuantityDto;
import com.beta.dto.product.ProductPropertiesDto;
import com.beta.entity.ProductItems;
import com.beta.entity.Users;
import com.beta.mapper.ProductItemsMapper;
import com.beta.service.*;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * ProductItems 表数据服务层接口实现类
 */
@Service
public class ProductItemsService extends SuperServiceImpl<ProductItemsMapper, ProductItems> implements IProductItemsService {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private IProductPropertiesService productPropertiesService;
    @Autowired
    private IUsersService usersService;
    @Autowired
    private IDateTimeService dateTimeService;

    @Override
    public ProductItemDto getProductItem(Integer productItemId) {
        if (Objects.isNull(productItemId)) {
            return null;
        }
        ProductItemDto productItemDto = baseMapper.selectOneById(productItemId);
        fillOptionsAndProperties(Arrays.asList(productItemDto));
        return productItemDto;
    }

    @Override
    public List<ProductItemDto> getProductItemsBatchByIds(List<Integer> productItemIds) {
        if (CollectionUtils.isEmpty(productItemIds)) {
            return Collections.emptyList();
        }
        List<ProductItemDto> productItemDtos = baseMapper.selectBatchByIds(productItemIds);
        fillOptionsAndProperties(productItemDtos);
        return productItemDtos;
    }

    @Override
    public Page<ProductItemDto> selectProductItems(Page<ProductItemDto> page, Integer categoryId, String cityCode, Integer userId) {
        if (Objects.isNull(categoryId)) {
            page.setRecords(baseMapper.selectProductByUserId(page, userId, cityCode));
        } else {
            page.setRecords(baseMapper.selectByCategoryId(page, categoryId, cityCode));
        }

        fillOptionsAndProperties(page.getRecords());
        return page;
    }

    private void fillOptionsAndProperties(List<ProductItemDto> productItemDtos) {
        if (CollectionUtils.isEmpty(productItemDtos)) {
            return ;
        }

        List<Integer> productItemIdList = new ArrayList<>();
        List<Integer> productIdList = new ArrayList<>();
        for (ProductItemDto productDto : productItemDtos) {
            productItemIdList.add(productDto.getId());
            productIdList.add(productDto.getProductId());
        }

        Map<Integer, List<ProductItemOptions>> productItemOptions = getProductItemOptionsBatch(productItemIdList);
        Map<Integer, List<ProductPropertiesDto>> productPropertiesDto = productPropertiesService.getProductPropertiesBatch(productIdList);

        Map<Integer, List<ProductItemOptions>> productItemOptionsMap = productItemOptions;
        Map<Integer, List<ProductPropertiesDto>> productPropertiesMap = productPropertiesDto;
        for (ProductItemDto productDto : productItemDtos) {
            productDto.setOptions(productItemOptionsMap.get(productDto.getId()));
            productDto.setProperties(productPropertiesMap.get(productDto.getProductId()));
        }
    }

    @Override
    public List<ProductItemOptions> getProductItemOptions(Integer productItemId) {
        if (Objects.isNull(productItemId)) {
            return Collections.emptyList();
        }

        Map<Integer, List<ProductItemOptions>> productItemOptionsMap = getProductItemOptionsBatch(Arrays.asList(productItemId));
        if (MapUtils.isEmpty(productItemOptionsMap) || !productItemOptionsMap.containsKey(productItemId)) {
            return Collections.emptyList();
        }
        return productItemOptionsMap.get(productItemId);
    }

    @Override
    public Map<Integer, List<ProductItemOptions>> getProductItemOptionsBatch(List<Integer> productItemIds) {
        if (CollectionUtils.isEmpty(productItemIds)) {
            return Collections.emptyMap();
        }

        List<ProductItemOptions> productItemOptionsList = baseMapper.selectProductItemOptionsBatch(productItemIds);
        return productItemOptionsList.stream().collect(Collectors.groupingBy(ProductItemOptions::getProductItemId));
    }


    @Override
    public Map<Integer, String> getProductItemOptionsTextBatch(List<Integer> productItemIds) {
        if (CollectionUtils.isEmpty(productItemIds)) {
            return Collections.emptyMap();
        }

        Map<Integer, List<ProductItemOptions>> productItemOptionsMap = getProductItemOptionsBatch(productItemIds);
        Map<Integer, String> productItemOptionTextMap = new HashMap<>(productItemOptionsMap.size());
        for (Map.Entry<Integer, List<ProductItemOptions>> entry: productItemOptionsMap.entrySet()) {
            productItemOptionTextMap.put(entry.getKey(), getProductItemOptionsText(entry.getValue()));
        }
        return productItemOptionTextMap;
    }

    private String getProductItemLevel(List<ProductItemOptions> productItemOptions) {
        if (CollectionUtils.isEmpty(productItemOptions)) {
            return "";
        }

        for (ProductItemOptions option : productItemOptions) {
            if ("level".equals(option.getName())) {
                return option.getValuePresentation();
            }
        }
        return "";
    }

    private String getProductItemOptionsText(List<ProductItemOptions> productItemOptions) {
        if (CollectionUtils.isEmpty(productItemOptions)) {
            return "";
        }

        return productItemOptions.stream().map(option -> {
            return option.getNamePresentation() + ":" + option.getValuePresentation();
        }).collect(Collectors.joining(","));
    }

    @Override
    public void reduceProductItemQuantityBatch(List<ProductItemQuantityDto> productItemQuantityList) {
        logger.info("扣除库存项 <== productItemQuantity:{}", JSON.toJSONString(productItemQuantityList));
        if (CollectionUtils.isEmpty(productItemQuantityList)) {
            return;
        }

        List<Integer> productItemIds = productItemQuantityList.stream().map(ProductItemQuantityDto::getProductItemId).collect(Collectors.toList());
        List<ProductItems> productItems = selectBatchIds(productItemIds);
        Map<Integer, ProductItems> productItemMap = productItems.stream().collect(Collectors.toMap(ProductItems::getId, item -> item));
        // TODO lock productItem ?
        for (ProductItemQuantityDto productItemQuantity : productItemQuantityList) {
            ProductItems productItem = productItemMap.get(productItemQuantity.getProductItemId());
            Integer reduceQuantity = productItemQuantity.getQuantity();
            if (productItem.getQuantity() < reduceQuantity) {
                throw new ServiceException("E40005");
            }
            if (Objects.nonNull(reduceQuantity) && reduceQuantity != 0) {
                baseMapper.reduceProductItemQuantity(productItemQuantity);
            }
        }
    }

    @Override
    public void restoreProductItemQuantityBatch(List<ProductItemQuantityDto> productItemQuantityList) {
        logger.info("恢复库存项 <== productItemQuantity:{}", JSON.toJSONString(productItemQuantityList));
        if (CollectionUtils.isEmpty(productItemQuantityList)) {
            return;
        }

        // TODO lock productItem ?
        for (ProductItemQuantityDto productItemQuantity : productItemQuantityList) {
            if (Objects.nonNull(productItemQuantity.getQuantity())) {
                baseMapper.restoreProductItemQuantity(productItemQuantity);
            }
        }
    }

    @Override
    public Page<ProductItemDto> selectDealerProductItems(Page<ProductItemDto> page, Integer userId, String cityCode) {
        List<ProductItemDto> productItemDtos = baseMapper.selectDealerProductItems(page, userId, cityCode);
        List<Integer> productItemIdList = new ArrayList<>();
        List<Integer> productIdList = new ArrayList<>();
        for (ProductItemDto searchList : productItemDtos) {
            productItemIdList.add(searchList.getId());
            productIdList.add(searchList.getProductId());
        }
        Map<Integer, List<ProductItemOptions>> productItemOptionsMap = getProductItemOptionsBatch(productItemIdList);
        Map<Integer, List<ProductPropertiesDto>> productPropertiesMap = productPropertiesService.getProductPropertiesBatch(productIdList);
        for (ProductItemDto productItemDto : productItemDtos) {
            productItemDto.setOptions(productItemOptionsMap.get(productItemDto.getId()));
            productItemDto.setProperties(productPropertiesMap.get(productItemDto.getProductId()));
        }
        page.setRecords(productItemDtos);
        return page;
    }

    @Override
    public Page<ProductItemDto> searchByName(Page<ProductItemDto> page, Integer userId, String keywords) {
        Users users = usersService.selectById(userId);
        String cityCode = users.getCityCode();
        List<ProductItemDto> productItemDtos = baseMapper.selectBySearch(page, keywords, cityCode);
        List<Integer> productItemIdList = new ArrayList<>();
        List<Integer> productIdList = new ArrayList<>();
        for (ProductItemDto searchList : productItemDtos) {
            productItemIdList.add(searchList.getId());
            productIdList.add(searchList.getProductId());
        }
        Map<Integer, List<ProductItemOptions>> productItemOptionsMap = getProductItemOptionsBatch(productItemIdList);
        Map<Integer, List<ProductPropertiesDto>> productPropertiesMap = productPropertiesService.getProductPropertiesBatch(productIdList);
        for (ProductItemDto productItemDto : productItemDtos) {
            productItemDto.setOptions(productItemOptionsMap.get(productItemDto.getId()));
            productItemDto.setProperties(productPropertiesMap.get(productItemDto.getProductId()));
        }
        page.setRecords(productItemDtos);
        return page;
    }

    @Override
    public void updateSliderImage(Integer productItemId, Integer sliderIndex, String imageFileName) {
        ProductItems productItems = new ProductItems()
                .setId(productItemId)
                .setUpdatedAt(dateTimeService.toDbDate());
        try {
            BeanUtils.setProperty(productItems, "slideImgPath" + sliderIndex, imageFileName);
            baseMapper.updateSelectiveById(productItems);
        } catch (Exception e) {
            throw new ServiceException(e);
        }
    }

    @Override
    public void deleteSliderImage(Integer productItemId, Integer sliderIndex) {
        updateSliderImage(productItemId, sliderIndex, "");
    }

}